package com.atguigu.gmall.activity.service.impl;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.activity.util.CacheHelper;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.MD5;
import com.atguigu.gmall.model.activity.OrderRecode;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.atguigu.gmall.model.order.OrderDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/9/9 9:37
 * @Version 1.0
 */
@Service
public class SeckillGoodsServiceImpl implements SeckillGoodsService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Override
    public Map<String, Object> trade(String userId) {
        //  创建一个map 集合
        HashMap<String, Object> hashMap = new HashMap<>();
        //  获取预下单数据
        OrderRecode orderRecode = (OrderRecode) this.redisTemplate.opsForHash().get(RedisConst.SECKILL_ORDERS, userId);
        //  判断
        if (null == orderRecode) {
            //  返回空
            return new HashMap<>();
        }
        //  获取秒杀商品
        SeckillGoods seckillGoods = orderRecode.getSeckillGoods();
        //  detailArrayList 本质是存储的orderDetail;
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setSkuId(seckillGoods.getSkuId());
        orderDetail.setSkuNum(orderRecode.getNum());
        orderDetail.setSkuName(seckillGoods.getSkuName());
        orderDetail.setImgUrl(seckillGoods.getSkuDefaultImg());
        orderDetail.setOrderPrice(seckillGoods.getCostPrice());
        ArrayList<OrderDetail> orderDetailArrayList = new ArrayList<>();
        orderDetailArrayList.add(orderDetail);

        //  存储页面渲染的数据
        hashMap.put("detailArrayList",orderDetailArrayList);
        hashMap.put("totalNum",orderRecode.getNum());
        hashMap.put("totalAmount",seckillGoods.getCostPrice());
        //  返回map 集合
        return hashMap;
    }

    @Override
    public Result checkOrder(Long skuId, String userId) {
        //  判断缓存中是否有用户key
        String userKey = RedisConst.SECKILL_USER+userId+":"+skuId;
        Boolean exist = this.redisTemplate.hasKey(userKey);
        //  判断 exist = true ;说明这个用户可能抢购成功.
        if (exist){
            //  判断用户是否抢购成功. hget key field;
            OrderRecode orderRecode = (OrderRecode) this.redisTemplate.opsForHash().get(RedisConst.SECKILL_ORDERS, userId);
            //  判断
            if (null != orderRecode){
                //  此时说明抢购成功. 提示去下单.
                return Result.build(orderRecode, ResultCodeEnum.SECKILL_SUCCESS);
            }
        }

        //  用户真正下单过订单.  在订单结算页面中点击提交订单，将数据保存到mysql 与 redis 中！
        //  redis key = seckill:orders:users field = userId  value = orderId  hget key field;
        String orderIdExist = (String) this.redisTemplate.opsForHash().get(RedisConst.SECKILL_ORDERS_USERS, userId);
        if (!StringUtils.isEmpty(orderIdExist)){
            //  提示抢购成功，查看我的订单。
            return Result.build(orderIdExist,ResultCodeEnum.SECKILL_ORDER_SUCCESS);
        }
        //  判断状态位
        String status = (String) CacheHelper.get(skuId.toString());
        if (StringUtils.isEmpty(status) || "0".equals(status)){
            return Result.build(null,ResultCodeEnum.SECKILL_FAIL);
        }
        //  默认状态排队中...
        return Result.build(null,ResultCodeEnum.SECKILL_RUN);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void seckillStock(Long skuId) {
        //  redis -- mysql
        //  redis -- hget key field;
        SeckillGoods seckillGoods = (SeckillGoods) this.redisTemplate.opsForHash().get(RedisConst.SECKILL_GOODS, skuId.toString());
        //  查看当前list的长度
        Long count = this.redisTemplate.opsForList().size(RedisConst.SECKILL_STOCK_PREFIX + skuId);
        seckillGoods.setStockCount(count.intValue());
        //  修改数据库。
        this.seckillGoodsMapper.updateById(seckillGoods);
        //  修改完成缓存数据.
        this.redisTemplate.opsForHash().put(RedisConst.SECKILL_GOODS,skuId.toString(),seckillGoods);
    }

    @Override
    public void seckillUser(UserRecode userRecode) {
        //  1.  校验状态位
        String status = (String) CacheHelper.get(userRecode.getSkuId().toString());
        if (StringUtils.isEmpty(status)){
            //  给信息提示
            return;
        }else if ("0".equals(status)){
            //  给信息提示
            return;
        }
        //  2. 判断这个用户是否秒杀过!   setnx key value 当 key 不存在的时候，才生效!
        //  userKey=seckill:user:userId:skuId value = userId
        String userKey = RedisConst.SECKILL_USER + userRecode.getUserId()+":"+userRecode.getSkuId();
        Boolean result = this.redisTemplate.opsForValue().setIfAbsent(userKey, userRecode.getUserId(), RedisConst.SECKILL__TIMEOUT, TimeUnit.SECONDS);
        //  判断 result = true: 说没有购买过 result=false说明购买过.
        if (!result){
            return;
        }
        //  3. 利用redis-list 从库存中减库存.lpush key value  rpop key
        String skuIdExist = (String) this.redisTemplate.opsForList().rightPop(RedisConst.SECKILL_STOCK_PREFIX + userRecode.getSkuId());
        if (StringUtils.isEmpty(skuIdExist)){
            //  说明当前商品已售罄.
            this.redisTemplate.convertAndSend("seckillpush",userRecode.getSkuId()+":0");
            return;
        }

        //  4. 将秒杀的数据保存到缓存中---预下单成功. 抽象一个实体类
        OrderRecode orderRecode = new OrderRecode();
        orderRecode.setUserId(userRecode.getUserId());
        orderRecode.setNum(1);
        orderRecode.setSeckillGoods(this.getSeckillGoods(userRecode.getSkuId()));
        orderRecode.setOrderStr(MD5.encrypt(userRecode.getSkuId()+userRecode.getUserId()));
        //  存储到缓存 hset key field value;  谁的预下单记录  --- 说明这个人已经有抢购资格了！
        this.redisTemplate.opsForHash().put(RedisConst.SECKILL_ORDERS, orderRecode.getUserId(), orderRecode);

        //  发送消息更新库存.
        rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_SECKILL_STOCK,MqConst.ROUTING_SECKILL_STOCK,userRecode.getSkuId());
    }

    /**
     *
     * @param skuId     秒杀商品Id
     * @param userId    用户Id
     * @param skuIdStr  前端传递的抢购码
     * @return
     */
    @Override
    public Result seckillOrder(Long skuId, String userId,String skuIdStr) {
        //  1.  校验抢购码
        if (!skuIdStr.equals(MD5.encrypt(userId+skuId))){
            //  给信息提示
            return Result.fail().message("校验抢购码失败");
        }
        //  2.  校验状态位 本地缓存的map中. skuId:1 skuId:0
        String status = (String) CacheHelper.get(skuId.toString());
        if (StringUtils.isEmpty(status)){
            //  给信息提示
            return Result.fail().message("状态位异常");
        }else if ("0".equals(status)){
            //  给信息提示
            return Result.fail().message("商品已售罄");
        }else {
            //  3.  验证通过之后，将userId 与 skuId 统一放入队列中.
            UserRecode userRecode = new UserRecode();
            userRecode.setUserId(userId);
            userRecode.setSkuId(skuId);

            //  将这个对象发送到mq中.
            this.rabbitService.sendMsg(MqConst.EXCHANGE_DIRECT_SECKILL_USER,MqConst.ROUTING_SECKILL_USER,userRecode);
            //  默认返回200
            return Result.ok();
        }
    }

    @Override
    public SeckillGoods getSeckillGoods(Long skuId) {
        //  hget key field;
        SeckillGoods seckillGoods = (SeckillGoods) this.redisTemplate.opsForHash().get(RedisConst.SECKILL_GOODS, skuId.toString());
        return seckillGoods;
    }

    @Override
    public List<SeckillGoods> findAll() {
        //  查询所有：hvals key
        List<SeckillGoods> seckillGoodsList = this.redisTemplate.opsForHash().values(RedisConst.SECKILL_GOODS);
        //  返回秒杀列表
        return seckillGoodsList;
    }


}
